
//{{{ file documentation -------------------------------------------------------

/*!
 * @file     textedit.cpp
 * @brief    dicodor text edition widget class implementation
 */

//}}} --------------------------------------------------------------------------
//{{{ includes / predeclarations -----------------------------------------------

// @ (#) $Id:$

#include "textedit.h"

#include <QtGui/QAction>
#include <QtGui/QWidgetAction>
#include <QtGui/QGridLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QMessageBox>
#include	 <QDebug>

//}}} --------------------------------------------------------------------------
//{{{ TextEdit -----------------------------------------------------------------
//}}} --------------------------------------------------------------------------
//{{{ .TextEdit (QWidget * parent) --------------------------------------------

TextEdit::TextEdit (QWidget * parent) :
	QTextEdit (parent)
{
	m_doc = document ();
	m_doc->setDocumentMargin (10);

	//initialisation de m_toReplace

	m_toReplace.insert (" .", ".");
	m_toReplace.insert (" ,", ",");
	m_toReplace.insert ("( ", "(");
	m_toReplace.insert (" )", ")");


	setAcceptRichText (true);
	createCharMenu ();

	connect (m_doc,
			 SIGNAL(contentsChange(int,int,int)),
			 this,
			 SLOT(onDocContentsChange(int,int,int)));
}

//}}} --------------------------------------------------------------------------
//{{{ .~TextEdit () -------------------------------------------------------------

TextEdit::~TextEdit ()
{
}

//}}} --------------------------------------------------------------------------
//{{{ .void .createCharMenu () --------------------------------------------------

void TextEdit::createCharMenu ()
{
	m_charMenu   = new QMenu (tr ("Insérer un caractère..."), this);

	// ** suppression des tentatives avec un grid layout + m_charWidget
	// je souhaitais afficher le sous-menu sous forme de tableau


	// critères de sélection des caractères à afficher

	for (ushort index = 1 ; index <= 0xff ; index++) {
		const QChar car (index);

		// as I never remember operator precedence, I change this

		if (true)
		{
			if (car.isLetterOrNumber ()) continue;
			if (! car.isPrint ()       ) continue;
			if (car.toLatin1 () == car ) continue;
			if (car.isSpace ()         ) continue;

			QWidgetAction * act = new QWidgetAction (m_charMenu);
			act->setText (QString (car));
			m_charMenu->addAction (act);
		}
		else if (! car.isLetterOrNumber ()
				 && car.isPrint ()
				 && (car.toLatin1 () != car)
				 && ! car.isSpace ())
		{
			QWidgetAction * act = new QWidgetAction (m_charMenu);
			act->setText (QString (car));
			m_charMenu->addAction (act);
		}
	}
}

//------------------------------------------------------------
/**
 * @brief TextEdit::contextMenuEvent
 * @param event
 */
void TextEdit::contextMenuEvent (QContextMenuEvent * event)
{
	if (!textCursor ().hasSelection ()) {
		// mettre le curseur à l'endroit du clic

		setTextCursor (cursorForPosition (event->pos ()));
	}

	QTextCursor cursor (textCursor ());

	QMenu* menu;
	if (cursor.charFormat ().underlineStyle () == QTextCharFormat::SpellCheckUnderline) {
		cursor.select (QTextCursor::WordUnderCursor);
		QString misspelledWord (cursor.selectedText ());
		QStringList suggests (m_spell.suggestionsFor (misspelledWord));

		menu = new QMenu (this);
		if (suggests.isEmpty ()) {  // pas de suggestion
			QAction* tempAction = new QAction ("(Aucune suggestion trouvée)", menu);
			tempAction->setDisabled (true);
			QFont font;
			font.setItalic (true);
			tempAction->setFont (font);
			menu->addAction (tempAction);
		}
		else
		{
			QMenu* menuSugg = new QMenu (tr ("Remplacer ici par"), menu);

			foreach (const QString& sugg, suggests)
			{
				QAction* tempAction = new QAction (sugg, menuSugg);
				tempAction->setData (MenuSuggestion);
				QFont font;
				font.setBold (true);
				tempAction->setFont (font);
				menuSugg->addAction (tempAction);
			}
			menu->addMenu (menuSugg);

			QMenu* menuAlwaysReplace = new QMenu (tr ("Toujours remplacer par"), menu);

			foreach (const QString& sugg, suggests)
			{
				QAction* tempAction = new QAction (sugg, menuSugg);
				tempAction->setData (MenuAlwaysReplace);
				QFont font;
				font.setBold (true);
				tempAction->setFont (font);
				menuAlwaysReplace->addAction (tempAction);
			}
			menu->addMenu (menuAlwaysReplace);
		}

		menu->addSeparator ();

		{
			QAction* tempAction = new QAction (tr ("Ajouter"), menu);
			tempAction->setIcon (QIcon::fromTheme ("accessories-dictionary"));
			tempAction->setData (MenuAddToDic);
			menu->addAction (tempAction);

			tempAction = new QAction (tr ("Ignorer"), menu);
			tempAction->setIcon (QIcon::fromTheme ("media-skip-forward"));
			tempAction->setData (MenuSkip);
			menu->addAction (tempAction);

			tempAction = new QAction (tr ("Supprimer"), menu);
			tempAction->setIcon (QIcon::fromTheme ("edit-delete"));
			tempAction->setData (MenuDelete);
			menu->addAction (tempAction);
		}

		// menu du correcteur
		QAction * action = menu->exec (event->globalPos ());
		if (action)
		{
			switch (action->data ().toInt ())
			{
			case MenuSuggestion:
			{
				int cursorPos = cursor.position ();
				cursor.select (QTextCursor::WordUnderCursor);
				QString bad (cursor.selectedText ());
				QString good (action->text ());
				cursor.select (QTextCursor::Document);
				cursor.beginEditBlock ();
				cursor.insertText (HSpell::replaced (toPlainText (), bad, good));
				cursor.endEditBlock ();
				cursor.setPosition (cursorPos);
				setTextCursor (cursor);
			}
			break;

			case MenuAlwaysReplace:
			{
//				int cursorPos = cursor.position ();
//				cursor.select (QTextCursor::WordUnderCursor);
//				QString bad (cursor.selectedText ());
//				QString good (action->text ());
//				cursor.select (QTextCursor::Document);
//				cursor.beginEditBlock ();
//				cursor.insertText (HSpell::replaced (toPlainText (), bad, good));
//				cursor.endEditBlock ();
//				cursor.setPosition (cursorPos);
//				setTextCursor (cursor);
			}
			break;
			case MenuAddToDic:
				m_spell.add (cursor.selectedText ());
			break;

			case MenuSkip:
				//				m_ortho->addToIgnoreList (misspelledWord);
				//				forceUpdate ();	// force un recalcul
			break;

			case MenuDelete:
				cursor.deleteChar ();
				forceUpdate ();	// force un recalcul
			break;
			}
		}
	}
	else	// menu standard de l'éditeur, amélioré
	{
		menu = createStandardContextMenu ();
		menu->addSeparator ();
		menu->addMenu (m_charMenu);

		QAction * action = menu->exec (event->globalPos ());

		if (action) {
			const QString& car (action->text ());
			if (car.length () == 1) {
				insertPlainText (car);
			}
		}
	}

	delete menu;
}
//-------------------------------------------------
/**
 * @brief TextEdit::onDocContentsChange
 */
void TextEdit::onDocContentsChange (int, int, int)
{
	if (m_doc->isEmpty ()) {
		emit documentIsEmpty (true);
		return;
	}

	emit documentIsEmpty (false);
	emit documentModified (true);

	// effacer les soulignés
	QTextCursor cursor (m_doc);
	cursor.select (QTextCursor::Document);
	QTextCharFormat standardFormat;
	cursor.setCharFormat (standardFormat);

	// préparer le format "souligné en vaguelettes"
	QTextCharFormat alertFormat;
	alertFormat.setUnderlineColor (m_config->optionUnderlineColor ());
	alertFormat.setUnderlineStyle (QTextCharFormat::SpellCheckUnderline);

	// parcourir le texte en soulignant les mots mal orthographiés
	//	QStringList misspelled (m_ortho->misspelledWords (m_doc->toPlainText ()));
	QStringList misspelled (m_spell.misspelledWords (m_doc->toPlainText ()));
	foreach (const QString& word, misspelled) {
		QTextCursor cursor (m_doc);
		cursor.setPosition (0);
		// recherche de chacun des mots depuis le début
		while (true) {
			cursor = m_doc->find (word, cursor, QTextDocument::FindCaseSensitively | QTextDocument::FindWholeWords);
			if (cursor.isNull ()) break;

			cursor.setCharFormat (alertFormat);
		}
	}
}

//--------------------------------------------------------------------------
/**
 * @brief TextEdit::open
 * @param path
 * @return
 */

bool TextEdit::open (const QString & path)
{
	QString result;
	bool ok = false;

	if (!path.isEmpty()) {

		QString fileType (Tools::fileType (path));
		qDebug () << "type de fichier :" << fileType;

		if (!fileType.contains ("text")) {
			emit message (tr ("%1 n'est pas reconnu comme fichier texte simple ou HTML"). arg (path));
			QMessageBox::warning	 (this,
									  tr ("Attention..."),
									  tr ("Dicodor ne sait ouvrir que des fichiers\nde type texte ou HTML"),
									  QMessageBox::Ok,
									  QMessageBox::Ok);
			ok = false;
		}
		else {
			QFile file (path) ;
			if (! (file.exists () && file.open (QIODevice::ReadOnly | QIODevice::Text))) {
				ok = false;
			}
			else {
				QTextStream in (& file) ;
				result = in.readAll ();
				if (fileType.contains ("html")) {
					m_doc->setHtml (result);
				}
				else {
					m_doc->setPlainText (result) ;
				}

				m_doc->setModified (false) ;
				setDocumentTitle (path);

				ok = true;
			}
		}
	}

	//    normalizeText ();
	emit documentIsEmpty (m_doc->isEmpty ());
	return ok;
}
//------------------------------------------
/**
 * @brief TextEdit::saveAs
 * @param path
 * @return
 */
bool TextEdit::saveAs (const QString &path)
{
	return saveAs (path, m_config->optionSaveFormat ());

}
//--------------------------------------------------------------------------------------------
/**
 * @brief TextEdit::saveAs
 * @param path
 * @param format
 * @return
 */
bool TextEdit::saveAs (const QString & path, const QByteArray & format)
{
	if (path.isEmpty ()) return false;

	QTextDocument doc;

	QString plainText (m_doc->toPlainText ());
	QString html (m_doc->toHtml (QByteArray ("utf-8")));

	QString filePath (path);

	if (format == "PDF")
	{
		return false;
	}

	if (format == "plaintext") {
		doc.setPlainText (plainText);
		filePath += ".txt";
	}

	if (format == "ODF") {
		doc.setHtml (html);
		filePath += ".odt";
	}

	if (format == "HTML") {
		doc.setHtml (html);
		filePath += ".html";
	}

	QTextDocumentWriter writer (filePath, format);

	bool ok = writer.write (&doc);

	return ok;

}

/**
 * @brief TextEdit::normalizeText
 */
void TextEdit::normalizeText()
{
	return;
	QString text (toPlainText ().simplified ());


	QMap <QString, QString>::ConstIterator iter;
	for (iter = m_toReplace.constBegin () ; iter != m_toReplace.constEnd () ; iter++)
	{
		text.replace (iter.key (), iter.value ());
	}

	setPlainText (text);
}

